﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

namespace AOUtils.Libraries
{
    public class OptimizedItem : IComparable
    {
        public OptimizedItem()
        {
            OnWear = new OnWear();
            ToUse = new OptimizedRequirementCollection();
            ToWear = new OptimizedRequirementCollection();
            ToWield = new OptimizedRequirementCollection();
        }
        public static explicit operator OptimizedItem(Item item)
        {
            OptimizedItem oitem = new OptimizedItem();
            oitem.Id = item.Id;
            oitem.Name = item.Name;
            oitem.Ql = item.Ql;
            oitem.Type = item.Type;
            oitem.Unique = (item.Flags & Flags.Unique) > 0;
            oitem.Icon = item.Icon;
            oitem.Flags = item.Flags;
            oitem.Slot = item.Slot;
            oitem.EquipmentPage = item.EquipmentPage;

            if (item.Events.Contains(EventType.OnWear))
            {
                foreach (Function func in item.Events[EventType.OnWear].Functions)
                {
                    //FunctionType ftype = (FunctionType)Enum.Parse(typeof(FunctionType), func.Name);
                    TargetType ttype = (TargetType)Enum.Parse(typeof(TargetType), func.Target);
                    if (!oitem.OnWear.Functions.Contains(func.Name))
                    {
                        FunctionList flist = new FunctionList();
                        flist.Type = func.Name;
                        oitem.OnWear.Functions.Add(flist);
                    }
                    Target t = new Target();
                    t.Type = (TargetType)Enum.Parse(typeof(TargetType), func.Target);
                    t.Arguments = new List<Argument>();
                    t.Arguments.AddRange(func.Arguments);
                    if (!oitem.OnWear.Functions[func.Name].Targets.Contains(ttype))
                    {
                        TargetList tlist = new TargetList();
                        tlist.Type = ttype;
                        oitem.OnWear.Functions[func.Name].Targets.Add(tlist);
                    }
                    foreach (Argument arg in func.Arguments)
                    {
                        List<OptimizedRequirement> reqs = new List<OptimizedRequirement>();
                        foreach (Requirement req in func.Requirements)
                            reqs.Add(req);
                        oitem.OnWear.Functions[func.Name].Targets[ttype].Arguments.Add(new OptimizedArgument(arg, reqs));
                    }
                }
            }
            foreach (Action action in item.Actions)
            {
                if (item.Actions.Contains(ActionType.ToUse))
                {
                    List<OptimizedRequirement> reqs = new List<OptimizedRequirement>();
                    foreach (Requirement req in action.Requirements)
                        oitem.ToUse.Requirements.Add(req);
                }
                if (item.Actions.Contains(ActionType.ToWear))
                {
                    List<OptimizedRequirement> reqs = new List<OptimizedRequirement>();
                    foreach (Requirement req in action.Requirements)
                        oitem.ToWear.Requirements.Add(req);
                }
                if (item.Actions.Contains(ActionType.ToWield))
                {
                    List<OptimizedRequirement> reqs = new List<OptimizedRequirement>();
                    foreach (Requirement req in action.Requirements)
                        oitem.ToWield.Requirements.Add(req);
                }
            }
            return oitem;
        }

        [XmlAttribute("id")]
        public int Id
        {
            get;
            set;
        }
        [XmlAttribute("name")]
        public string Name
        {
            get;
            set;
        }
        [XmlAttribute("ql")]
        public int Ql
        {
            get;
            set;
        }
        [XmlAttribute("itemtype")]
        public ItemType Type
        {
            get;
            set;
        }
        [XmlAttribute("unique")]
        public bool Unique
        {
            get;
            set;
        }
        [XmlElement("icon")]
        public int Icon
        {
            get;
            set;
        }
        [XmlElement("flags")]
        public Flags Flags
        {
            get;
            set;
        }
        [XmlIgnore]
        public bool Social
        {
            get
            {
                return (Flags & Flags.ItemSocialArmour) > 0;
            }
        }
        [XmlElement("slot")]
        public Slot Slot
        {
            get;
            set;
        }
        [XmlElement("equipmentpage")]
        public EquipmentPage EquipmentPage
        {
            get;
            set;
        }
        [XmlElement("onwear")]
        public OnWear OnWear
        {
            get;
            set;
        }
        [XmlElement("touse")]
        public OptimizedRequirementCollection ToUse
        {
            get;
            set;
        }
        [XmlElement("towear")]
        public OptimizedRequirementCollection ToWear
        {
            get;
            set;
        }
        [XmlElement("towield")]
        public OptimizedRequirementCollection ToWield
        {
            get;
            set;
        }
        [XmlIgnore]
        public string SortSkill
        {
            get;
            set;
        }
        public SortedDictionary<string, int> GetSkillValues()
        {
            SortedDictionary<string, int> skills = new SortedDictionary<string, int>();
            if (OnWear.Functions.Contains(FunctionType.Modify) && OnWear.Functions[FunctionType.Modify].Targets.Contains(TargetType.Wearer))
            {
                KeyValuePair<string, int> kvp;
                for (int x = OnWear.Functions[FunctionType.Modify].Targets[TargetType.Wearer].Arguments.Count - 1; x >= 0; x -= 2)
                {
                    int i;
                    if (int.TryParse(OnWear.Functions[FunctionType.Modify].Targets[TargetType.Wearer].Arguments[x].Value, out i))
                    {
                        kvp = new KeyValuePair<string, int>(
                            OnWear.Functions[FunctionType.Modify].Targets[TargetType.Wearer].Arguments[x - 1].Value,
                            int.Parse(OnWear.Functions[FunctionType.Modify].Targets[TargetType.Wearer].Arguments[x].Value));
                    }
                    else
                    {
                        kvp = new KeyValuePair<string, int>(
                            OnWear.Functions[FunctionType.Modify].Targets[TargetType.Wearer].Arguments[x].Value,
                            int.Parse(OnWear.Functions[FunctionType.Modify].Targets[TargetType.Wearer].Arguments[x - 1].Value));
                    }
                    if (!skills.ContainsKey(kvp.Key))
                        skills.Add(kvp.Key, kvp.Value);
                }
            }
            if (OnWear.Functions.Contains(FunctionType.Modify) && OnWear.Functions[FunctionType.Modify].Targets.Contains(TargetType.Target))
            {
                KeyValuePair<string, int> kvp;
                for (int x = OnWear.Functions[FunctionType.Modify].Targets[TargetType.Target].Arguments.Count - 1; x >= 0; x -= 2)
                {
                    int i;
                    if (int.TryParse(OnWear.Functions[FunctionType.Modify].Targets[TargetType.Target].Arguments[x].Value, out i))
                    {
                        kvp = new KeyValuePair<string, int>(
                            OnWear.Functions[FunctionType.Modify].Targets[TargetType.Target].Arguments[x - 1].Value,
                            int.Parse(OnWear.Functions[FunctionType.Modify].Targets[TargetType.Target].Arguments[x].Value));
                    }
                    else
                    {
                        kvp = new KeyValuePair<string, int>(
                            OnWear.Functions[FunctionType.Modify].Targets[TargetType.Target].Arguments[x].Value,
                            int.Parse(OnWear.Functions[FunctionType.Modify].Targets[TargetType.Target].Arguments[x - 1].Value));
                    }
                    if (!skills.ContainsKey(kvp.Key))
                        skills.Add(kvp.Key, kvp.Value);
                }
            }
            /*if (OnWear.Functions.Contains(FunctionType.Modify) && OnWear.Functions[FunctionType.Modify].Targets.Contains(TargetType.User))
            {
                KeyValuePair<string, int> kvp;
                for (int x = OnWear.Functions[FunctionType.Modify].Targets[TargetType.User].Arguments.Count - 1; x >= 0; x -= 2)
                {
                    int i;
                    if (int.TryParse(OnWear.Functions[FunctionType.Modify].Targets[TargetType.User].Arguments[x].Value, out i))
                    {
                        kvp = new KeyValuePair<string, int>(
                            OnWear.Functions[FunctionType.Modify].Targets[TargetType.User].Arguments[x - 1].Value,
                            int.Parse(OnWear.Functions[FunctionType.Modify].Targets[TargetType.User].Arguments[x].Value));
                    }
                    else
                    {
                        kvp = new KeyValuePair<string, int>(
                            OnWear.Functions[FunctionType.Modify].Targets[TargetType.User].Arguments[x].Value,
                            int.Parse(OnWear.Functions[FunctionType.Modify].Targets[TargetType.User].Arguments[x - 1].Value));
                    }
                    if (!skills.ContainsKey(kvp.Key))
                        skills.Add(kvp.Key, kvp.Value);
                }
            }*/
            return skills;
        }

        public List<OptimizedRequirement> GetRequirements(string statistic)
        {
            List<OptimizedRequirement> reqs = new List<OptimizedRequirement>();
            foreach (OptimizedRequirement req in ToUse.Requirements)
                if (req.Statistic.Equals(statistic))
                    reqs.Add(req);
            foreach (OptimizedRequirement req in ToWear.Requirements)
                if (req.Statistic.Equals(statistic))
                    reqs.Add(req);
            foreach (OptimizedRequirement req in ToWield.Requirements)
                if (req.Statistic.Equals(statistic))
                    reqs.Add(req);
            return reqs;
        }

        [XmlIgnore]
        public List<OptimizedRequirement> HasFactionReq
        {
            get
            {
                return GetRequirements("Side");
            }
        }
        [XmlIgnore]
        public List<OptimizedRequirement> HasBreedReq
        {
            get
            {
                return GetRequirements("Breed");
            }
        }
        [XmlIgnore]
        public List<OptimizedRequirement> HasProfessionReq
        {
            get
            {

                List<OptimizedRequirement> list = GetRequirements("Profession");
                list.AddRange(GetRequirements("VisualProfession"));
                if (list.Count == 0 && (this.Type & ItemType.Implant) > 0)
                {
                    OptimizedRequirement req = new OptimizedRequirement();
                    req.Operator = OperatorType.NotEqualTo;
                    req.Value = "Shade";
                    req.Statistic = "Profession";
                    list.Add(req);
                }
                else if (list.Count == 0 && (this.Type & ItemType.Spirit) > 0)
                {
                    OptimizedRequirement req = new OptimizedRequirement();
                    req.Operator = OperatorType.EqualTo;
                    req.Value = "Shade";
                    req.Statistic = "Profession";
                    list.Add(req);
                }

                return list;
            }
        }

        #region IComparable Members

        public int CompareTo(object obj)
        {
            if (obj is OptimizedItem)
            {
                OptimizedItem item = obj as OptimizedItem;
                if (SortSkill != null && !SortSkill.Equals(""))
                {
                    return GetSkillValues()[SortSkill].CompareTo(item.GetSkillValues()[SortSkill]);
                }
                return item.Name.CompareTo(Name);
            }
            return -1;
        }

        #endregion
    }
}
